/**
 * @descript 本文件用于请求接口
 * @author jinzz
 * 暴露方法有
 * useAxios httpClient本体，适用于自定义请求方法或需要自定义参数
 * useGet
 * usePost
 * usePut
 * useDelete
 * usePadding
 * 
 * @example
 * usePost({
  url: '/api/postTable',
    params: {
      page: 1
    },
    data: {
      a: 1
    },
    loading: false
  }).then(d => {
  })
  .catch(e => {
  })
 * fixme: 需要将其改造，目前并非hooks,未来改造设想为：
 * const Service = useHttp(url)
 * Service.get().then(x => {})
 * Service.post().then(x => {})
 */


import router from '@/router'
import AxiosInstance, { AxiosRequestConfig, ParamsSerializerOptions } from 'axios'
import { ElLoading, ElMessage } from 'element-plus'
import qs from 'qs'
// 用来监控错误信息
import { AUTH_ERRORS } from '@/config'
import { useLocalStorage } from '@hooks/useLocalStorage'
export interface AxiosConfig extends AxiosRequestConfig {
  loading?: Boolean
}

export interface AxiosParams {
  url: String,
  data?: Object,
  params?: Object
  config?: AxiosConfig
}

export interface HttpError {
  result?: {
    data ?: object
  },
  message: string,
  status?: number | string
}

export type AxiosPromise = Promise<any>

let httpClient = AxiosInstance.create({
  baseURL: '/', // api base_url
  timeout: 60 * 1000 * 5 // 请求超时时间
})


/* loading */
let loadingInstance: any = null
const showLoading = () => {
  loadingInstance = ElLoading.service({
    fullscreen: true
  })  
}
const hideLoading = () => {
  if (loadingInstance) {
    loadingInstance.close()
    loadingInstance = null
  }
}

const handleError = (error: HttpError) => {
  if (AUTH_ERRORS[error.status as keyof typeof AUTH_ERRORS]) {
    router.replace('/login')
  }

  ElMessage({
    message: error?.message || '接口请求错误',
    type: 'error',
    center: true
  })
  return Promise.reject(error?.message || '接口请求错误')
}

// AxiosResponse
const tokenInterceptor = (config: any)  => {
  const { state } = useLocalStorage('token')
  config.headers['app-code'] = 'iop'
  config.headers['authorization'] = 'Bearer ' + state.value
  return config
}

// 格式化参数拦截器
const paramsInterceptor = (config: any) => {
  config.paramsSerializer = (params: Object) => {
    return qs.stringify(params) as ParamsSerializerOptions
  }
  return config
}

httpClient.interceptors.request.use(tokenInterceptor)
httpClient.interceptors.request.use(paramsInterceptor)
httpClient.interceptors.response.use(
  ({ data = {} }) => {
    if (data.status === '200') {
      return data.result
    }
    return handleError(data)
  },
  // 接口失败回调
  ({ response = {} }) => {
    return handleError({
    status: response.status||98740,
    result: response||{},
    message: ''
})
  }
)

const __ajax = async (
  method: String, 
  {
    params = {},
    config = { loading: false },
    data = {},
    url
  } : AxiosParams
): Promise<unknown> => {
  if (config.loading) {
    showLoading()
    delete config.loading
  }
  const result = await httpClient(
    Object.assign(
      config,
      { url: '/api' + url,
        data, params, method
      },
    )
  )
  hideLoading()
  return result
}

const useGet = (args: any) => {
  return __ajax('get', args)
}

const usePost = async (args: any) => {
  return __ajax('post', args)
}

const usePut = async (args: any) => {
  return __ajax('put', args)
}

const useDelete = async (args: any) => {
  return __ajax('delete', args)
}


const usePadding = (list: AxiosPromise[]) => {
  return Promise.all(list)
}

export {
  httpClient as useAxios,
  useGet,
  usePost,
  useDelete,
  usePut,
  usePadding
}

export default AxiosInstance